%option yylineno
%{

#include "lexical.h"
#include "syntax.tab.h"

void lexPrint(char *str){
    #ifdef LOCAL
    fprintf(stderr,"lexPrint:Line %d :input  %s : %s\n",yylineno,str,yytext);
    #endif
}
void lexerror(char *msg);
void sperror(char *msg);
tree_node_t * generate_lex_node(
	char *name, 
	data_type_t data_type, 
	void * lex_data
);

int lexError=0;
int lexLastErrorLine = 0;
int yycolumn = 1;
extern tree_t mTreeRoot;

#define YY_USER_ACTION \
	yylloc.first_line = yylloc.last_line = yylineno; \
	yylloc.first_column = yycolumn; \
	yylloc.last_column = yycolumn + yyleng - 1; \
	yycolumn += yyleng;
%}

%x COMMENT_BLOCK  

DIGIT [0-9]
DIGITS {DIGIT}+
LETTER [a-zA-Z_]
IDCHAR {LETTER}|{DIGIT}
DOT \.
WHITESPACE [ \t\r\n]+
ID {LETTER}{IDCHAR}*
IDERROR {DIGITS}{LETTER}{IDCHAR}*
DEC 0|([1-9][0-9]*)
FLOAT {DIGITS}{DOT}{DIGITS}
FLOATe ({DOT}{DIGITS}|{DIGITS}{DOT}|{DIGITS}{DOT}{DIGITS})([eE][+-]?{DIGITS})
FLOATERROR ({DOT}{DIGITS}|{DIGITS}{DOT}|{DIGITS}{DOT}{DIGITS})([eE][+-]?)|({DOT}[eE][+-]?{DIGITS}?)|({DIGITS}[eE][+-]?{DIGITS}?)
SEMI ";"
COMMA ","
ASSIGNOP "="
RELOP ">"|"<"|">="|"<="|"=="|"!="
PLUS "+"
MINUS "-"
STAR "*"
DIV  "/"
AND "&&"
OR "||"
NOT "!"
TYPE "int"|"float"
LP "("
RP ")"
LB "["
RB "]"
LC "{"
RC "}"
STRUCT "struct"
RETURN "return"
IF "if"
ELSE "else"
WHILE "while"
%%
"//"    {
			char c = input();
			while (c != '\n') c = input();
            sperror("special error");
        }
"/*"    {
			sperror("special error");
            BEGIN(COMMENT_BLOCK); // 进入注释块模式
        }

<COMMENT_BLOCK>"*/"   {
                sperror("special error");
				BEGIN(INITIAL);
            }
	

<COMMENT_BLOCK>"*" {
    // 遇到 * 时打印错误
    sperror("special error");
}

<COMMENT_BLOCK>\n {
    
    { yycolumn = 1;}
}

<COMMENT_BLOCK>. {
    // 忽略注释内的所有字符
    
}

{TYPE} 			{ yylval.node = generate_lex_node("TYPE", TYPE_DATA, NULL); 		return TYPE;}
{STRUCT} 		{ yylval.node = generate_lex_node("STRUCT", DEFAULT_DATA, NULL); 	return STRUCT;}
{RETURN} 		{ yylval.node = generate_lex_node("RETURN", DEFAULT_DATA, NULL); 	return RETURN;}
{IF} 			{ yylval.node = generate_lex_node("IF", DEFAULT_DATA, NULL); 		return IF;}
{ELSE} 			{ yylval.node = generate_lex_node("ELSE", DEFAULT_DATA, NULL); 		return ELSE;}
{WHILE} 		{ yylval.node = generate_lex_node("WHILE", DEFAULT_DATA, NULL);		return WHILE;}
{SEMI} 			{ yylval.node = generate_lex_node("SEMI", DEFAULT_DATA, NULL);		return SEMI;}
{COMMA} 		{ yylval.node = generate_lex_node("COMMA", DEFAULT_DATA, NULL);		return COMMA;}
{ASSIGNOP} 		{ yylval.node = generate_lex_node("ASSIGNOP", DEFAULT_DATA, NULL);	return ASSIGNOP;}
{RELOP} 		{ yylval.node = generate_lex_node("RELOP", DEFAULT_DATA, NULL);		return RELOP;}
{PLUS}			{ yylval.node = generate_lex_node("PLUS", DEFAULT_DATA, NULL); 		return PLUS;}
{MINUS}			{ yylval.node = generate_lex_node("MINUS", DEFAULT_DATA, NULL);		return MINUS;}
{STAR}			{ yylval.node = generate_lex_node("STAR", DEFAULT_DATA, NULL);		return STAR;}
{DIV}			{ yylval.node = generate_lex_node("DIV", DEFAULT_DATA, NULL);		return DIV;}
{AND} 			{ yylval.node = generate_lex_node("AND", DEFAULT_DATA, NULL);		return AND;}
{OR} 			{ yylval.node = generate_lex_node("OR", DEFAULT_DATA, NULL);		return OR;}
{NOT} 			{ yylval.node = generate_lex_node("NOT", DEFAULT_DATA, NULL);		return NOT;}

{FLOATe} 		{ float f;		sscanf(yytext, "%f", &f);
			 	  yylval.node = generate_lex_node("FLOAT", FLOAT_DATA, &f);			return FLOAT;}
{FLOAT} 		{ float f;		sscanf(yytext, "%f", &f);
				  yylval.node = generate_lex_node("FLOAT", FLOAT_DATA, &f);			return FLOAT;}
{DEC} 			{ int i;		sscanf(yytext, "%d", &i);
				  yylval.node = generate_lex_node("INT", INT_DATA, &i);				return INT;}
{DOT} 			{ yylval.node = generate_lex_node("DOT", DEFAULT_DATA, NULL);		return DOT;}
{LP} 			{ yylval.node = generate_lex_node("LP", DEFAULT_DATA, NULL);		return LP;}
{RP} 			{ yylval.node = generate_lex_node("RP", DEFAULT_DATA, NULL);		return RP;}
{LB} 			{ yylval.node = generate_lex_node("LB", DEFAULT_DATA, NULL);		return LB;}
{RB} 			{ yylval.node = generate_lex_node("RB", DEFAULT_DATA, NULL);		return RB;}
{LC} 			{ yylval.node = generate_lex_node("LC", DEFAULT_DATA, NULL);		return LC;}
{RC} 			{ yylval.node = generate_lex_node("RC", DEFAULT_DATA, NULL);		return RC;}
{ID}			{ yylval.node = generate_lex_node("ID", ID_DATA, yytext);			return ID;}
\n	 			{ yycolumn = 1;}
{WHITESPACE} 	{ /* 忽略空白字符 */;  }			
. 				{ lexerror("unmatched character."); }
%%

tree_node_t * generate_lex_node(char *name, data_type_t data_type, void * lex_data) {
	lexPrint(name);
	node_data_t data = {
		.data = yytext,
		.data_type = data_type
	};
	if(lex_data != NULL){
		data.data = lex_data;
	}
	return create_and_init_node(name, data, LEX_NODE, yylineno);
}

void lexerror(char *msg){
	lexError += 1;
	if(last_error_line == yylineno){
		return;
	}
	printf("Error type A at Line %d: %s\n", yylineno, msg);
	last_error_line = lexLastErrorLine = yylineno;
}

void sperror(char *msg){
	lexError += 1;
	if(last_error_line == yylineno){
		return;
	}
	printf("Error type B at Line %d: %s.\n", yylineno, msg);
	last_error_line = lexLastErrorLine = yylineno;
}
